Repository navigation
fix(ci): prune 6 stale eslint suppressions that made npm run lint exit 2 (#15159 G-05) - #15283
Merged
diegosouzapw merged 2 commits intoOct 2, 2026
Conversation
…xit 2 (diegosouzapw#15159 G-05) ESLint fails an entire run when the suppressions file carries entries whose violation no longer occurs: There are suppressions left that do not occur anymore. To resolve this, re-run the command with `--prune-suppressions` … So the debt is not cosmetic — `npm run lint` exited **2** on every PR. The step in ci.yml is the `lint` job, which gates every other job through its own failure. Six entries were stale. All six are `@typescript-eslint/no-unused-vars`: open-sse/translator/request/openai-to-cursor.ts (3) src/app/(dashboard)/.../settings/components/SystemStorageTab.tsx (1) src/app/api/v1/vscode/[token]/combos/route.ts (1) src/app/api/v1/vscode/raw/[token]/combos/route.ts (1) src/lib/oauth/providers/ghe-copilot.ts (1) tests/unit/cursor-agent-session.test.ts (?) Each was re-linted directly with an EMPTY suppressions file and `no-unused-vars` forced to error: zero violations on all six. That check is also why pruning is safe to do on one platform and land on another — `no-unused-vars` is platform-independent, so the Windows dev machine and the Linux CI runner produce the same file. 1094 → 1088 suppressed violations; nothing else changed. ## Verification (release/v3.8.52 @ dbe703a) | Check | Before | After | | --- | --- | --- | | `npm run lint` | **exit 2** | **exit 0** | | `lint:json` totals (11786 files) | — | 0 errors, 0 warnings | | suppressed violations | 1094 | 1088 | | diff | — | exactly 6 removals, 1 insertion (trailing comma) | The ratchet metric does not move: the baseline note already records that `lint:json` measures 0 with suppressions applied, and a pruned entry was not counted before or after. ## Tests `tests/unit/build/eslint-suppressions-pruned.test.ts` — 6/6. Five are cheap and pin the invariant: the six known-stale entries stay gone, no empty file/rule buckets survive a hand-edit, suppression keys stay POSIX-relative (a backslash key silently stops matching, which looks identical to "unpruned" from the gate's exit code), and a `SHAPE-SANITY` case pins that the file is keyed by FILE first, then rule. That last one exists because the first draft of this suite got the nesting backwards — every lookup missed, and "no stale entries" passed **vacuously** while the gate was red. A test that cannot fail proves nothing; the sanity case is what makes the other four trustworthy. The sixth runs the real ESLint gate on the real repo (~3.5 min) and asserts it does not exit 2. Refs diegosouzapw#15159 (G-05)
This was referenced Oct 1, 2026
Merged
The CI lint job is the real gate; keep only the cheap invariant checks. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
diegosouzapw
merged commit Oct 2, 2026
d59c244
into
diegosouzapw:release/v3.8.52
37 of 41 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
npm run lintexits 2 on every PR:ESLint fails an entire run when the suppressions file carries entries whose
violation no longer occurs. So this is not cosmetic debt — it is a red
lintjobon the whole queue, and the
lintjob gates several others.Fix
Six entries were stale. All six are
@typescript-eslint/no-unused-vars:open-sse/translator/request/openai-to-cursor.tssrc/app/(dashboard)/dashboard/settings/components/SystemStorageTab.tsxsrc/app/api/v1/vscode/[token]/combos/route.tssrc/app/api/v1/vscode/raw/[token]/combos/route.tssrc/lib/oauth/providers/ghe-copilot.tstests/unit/cursor-agent-session.test.ts1094 → 1088 suppressed violations. The diff is exactly those 6 removals plus one
trailing comma; nothing else in the file moved.
Why this is safe to land from a Windows machine
Pruning on one platform and landing on another is only safe if the lint result is
platform-independent. Each of the six was re-linted directly with an empty
suppressions file and
no-unused-varsforced toerror:no-unused-varsis platform-independent, so the Windows dev machine and the LinuxCI runner produce the same pruned file. This is the check that makes the change
reviewable, so it is recorded here rather than left as "trust me, it's just
unused vars".
Verification (release/v3.8.52 @ dbe703a)
npm run lintlint:jsontotals (11786 files)The ratchet metric does not move. The baseline note for
eslintWarningsalreadyrecords that
lint:jsonmeasures 0 with suppressions applied, and a prunedentry was not counted before or after — so no
--updatetoquality-baseline.jsonis warranted (and none was made).
Tests
tests/unit/build/eslint-suppressions-pruned.test.ts— 6/6.Five are cheap and pin the invariant: the six known-stale entries stay gone, no
empty file/rule buckets survive a hand-edit, and suppression keys stay
POSIX-relative. That last one matters more than it looks — a backslash key
silently stops matching, which turns a suppressed warning back into a hard
failure and, from the gate's exit code, is indistinguishable from "unpruned".
The sixth runs the real ESLint gate on the real repo (~3.5 min) and asserts it
does not exit 2.
The test that guards the tests
There is a
SHAPE-SANITYcase because the first draft of this suite got the JSONnesting backwards. The suppressions file is keyed file → rule → count, not
rule → file → count:
{ "src/file.ts": { "@typescript-eslint/no-unused-vars": { "count": 1 } } }With the nesting inverted, every lookup missed and "none of the six known-stale
suppressions is still present" passed vacuously — green, while the gate was
red. The sanity case pins the shape so the other four cannot silently stop
testing anything.
Ordering note
This PR unblocks the
lintjob for every other #15159 PR. #15281 (G-01/G-02)and #15282 (G-04) will show a red
lintstep until this lands, because the basebranch carries the unpruned suppressions. Merging this one first is the cheapest
path to a readable CI signal on the rest.
Refs #15159 (G-05)